using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;

namespace Microsoft.SqlServer.Management.SqlManagerUI.Scripting
{
	internal class ScriptProcessor
	{
		private readonly ReadOnlyCollection<Urn> objectsToScript;

		private ScriptCommandFactory scriptCommandFactory;

		private ScriptingOptions scriptOptions;

        public event EventHandler ScriptingStarted;
        //{
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    add
        //    {
        //        this.ScriptingStarted = (EventHandler)Delegate.Combine(this.ScriptingStarted, value);
        //    }
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    remove
        //    {
        //        this.ScriptingStarted = (EventHandler)Delegate.Remove(this.ScriptingStarted, value);
        //    }
        //}

        public event EventHandler ScriptingCompleted;
        //{
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    add
        //    {
        //        this.ScriptingCompleted = (EventHandler)Delegate.Combine(this.ScriptingCompleted, value);
        //    }
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    remove
        //    {
        //        this.ScriptingCompleted = (EventHandler)Delegate.Remove(this.ScriptingCompleted, value);
        //    }
        //}

		public event EventHandler<ScriptingProgressEventArgs> ScriptingProgress;
        //{
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    add
        //    {
        //        this.ScriptingProgress = (EventHandler<ScriptingProgressEventArgs>)Delegate.Combine(this.ScriptingProgress, value);
        //    }
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    remove
        //    {
        //        this.ScriptingProgress = (EventHandler<ScriptingProgressEventArgs>)Delegate.Remove(this.ScriptingProgress, value);
        //    }
        //}

        public event EventHandler<ObjectScriptedEventArgs> ObjectScripted;
        //{
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    add
        //    {
        //        this.ObjectScripted = (EventHandler<ObjectScriptedEventArgs>)Delegate.Combine(this.ObjectScripted, value);
        //    }
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    remove
        //    {
        //        this.ObjectScripted = (EventHandler<ObjectScriptedEventArgs>)Delegate.Remove(this.ObjectScripted, value);
        //    }
        //}

		public event EventHandler<ScriptingErrorEventArgs> ScriptingError;
        //{
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    add
        //    {
        //        this.ScriptingError = (EventHandler<ScriptingErrorEventArgs>)Delegate.Combine(this.ScriptingError, value);
        //    }
        //    [MethodImpl(MethodImplOptions.Synchronized)]
        //    remove
        //    {
        //        this.ScriptingError = (EventHandler<ScriptingErrorEventArgs>)Delegate.Remove(this.ScriptingError, value);
        //    }
        //}

		private int TotalObjects
		{
			get
			{
				return this.objectsToScript.Count;
			}
		}

		public ScriptProcessor(IList<Urn> objectsToScript, ScriptingOptions scriptOptions, ScriptCommandFactory scriptCommandFactory)
		{
			if (objectsToScript == null)
			{
				throw new ArgumentNullException("objectsToScript");
			}
			if (scriptOptions == null)
			{
				throw new ArgumentNullException("scriptOptions");
			}
			if (scriptCommandFactory == null)
			{
				throw new ArgumentNullException("scriptCommandFactory");
			}
			this.objectsToScript = new ReadOnlyCollection<Urn>(objectsToScript);
			this.scriptCommandFactory = scriptCommandFactory;
			this.scriptOptions = scriptOptions;
		}

		public void GenerateScript()
		{
			int num = 0;
			this.OnScriptingStarted();
			foreach (Urn current in this.objectsToScript)
			{
				try
				{
					ScriptingOptions scriptingOptions = new ScriptingOptions(this.scriptOptions);
					this.GetScriptCommand(current, new ObjectScriptedHandler(this.ObjectScriptedObserver)).Script(current, scriptingOptions);
					num++;
					this.UpdatedObjectScriptingProgress(current, num);
				}
				catch (Exception error)
				{
					if (!this.ContinueScriptingOnError(current, error))
					{
						throw;
					}
				}
			}
			this.OnScriptingCompleted();
		}

		private ScriptCommand GetScriptCommand(Urn item, ObjectScriptedHandler scriptTarget)
		{
			return this.scriptCommandFactory.GetScriptCommand(item, scriptTarget);
		}

		private void ObjectScriptedObserver(Microsoft.SqlServer.Management.SqlManagerUI.ObjectInfo objectInfo, IEnumerable script, ScriptActions action)
		{
			ObjectScriptedEventArgs e = new ObjectScriptedEventArgs(objectInfo, script, action);
			this.OnObjectScripted(e);
		}

		private void UpdatedObjectScriptingProgress(Urn current, int countObjectsScripted)
		{
			ScriptingProgressEventArgs e = new ScriptingProgressEventArgs(current, countObjectsScripted, this.TotalObjects);
			this.OnScriptingProgress(e);
		}

		protected void OnObjectScripted(ObjectScriptedEventArgs e)
		{
			if (this.ObjectScripted != null)
			{
				this.ObjectScripted(this, e);
			}
		}

		private bool ContinueScriptingOnError(Urn current, Exception error)
		{
			ScriptingErrorEventArgs scriptingErrorEventArgs = new ScriptingErrorEventArgs(current, error);
			this.OnScriptingError(scriptingErrorEventArgs);
			return scriptingErrorEventArgs.ContinueScripting;
		}

		private void OnScriptingError(ScriptingErrorEventArgs e)
		{
			if (this.ScriptingError != null)
			{
				this.ScriptingError(this, e);
			}
		}

		protected void OnScriptingStarted()
		{
			if (this.ScriptingStarted != null)
			{
				this.ScriptingStarted(this, EventArgs.Empty);
			}
		}

		protected void OnScriptingCompleted()
		{
			if (this.ScriptingCompleted != null)
			{
				this.ScriptingCompleted(this, EventArgs.Empty);
			}
		}

		protected void OnScriptingProgress(ScriptingProgressEventArgs e)
		{
			if (this.ScriptingProgress != null)
			{
				this.ScriptingProgress(this, e);
			}
		}
	}
}
